iT邦幫忙

2024 iThome 鐵人賽

DAY 16
0
自我挑戰組

我的Java自學之路:一個轉職者的30篇技術統整系列 第 16

Java虛擬機器:JVM架構與記憶體模型

  • 分享至 

  • xImage
  •  

引言

Java虛擬機器(JVM)是Java程式語言的核心組件,扮演著至關重要的角色,使得Java能夠實現「一次編寫,到處執行」的理念。JVM不僅負責執行Java位元組碼,還管理記憶體、確保安全性,並提供跨平台的能力。本文將深入探討JVM的架構和記憶體模型,幫助讀者更好地理解Java程式的執行過程,並為效能調校和問題排除奠定基礎。我們將從JVM的整體架構開始,然後詳細介紹其記憶體模型,最後討論JVM的執行過程、優化技術和調校方法。

JVM架構概覽

Java虛擬機器(JVM)的架構可以分為三個主要部分:類別載入器子系統、執行引擎和執行時期資料區。

  1. 類別載入器子系統:
    負責載入、連結和初始化類別檔案。遵循委派模型,包含啟動類別載入器、延伸類別載入器和應用程式類別載入器。這個子系統確保Java程式的動態載入特性。

  2. 執行引擎:
    是JVM的核心,負責執行Java位元組碼。包含以下組件:

    • 直譯器:逐行解釋和執行位元組碼。
    • 即時(JIT)編譯器:將熱點程式碼編譯為本機機器碼,提高執行效率。
    • 垃圾回收器:自動管理記憶體,回收不再使用的物件。
  3. 執行時期資料區:
    包括方法區、堆、Java堆疊、程式計數器和本地方法堆疊。這些區域用於儲存程式執行過程中的各種資料,如類別資訊、物件實例、區域變數等。

JVM的這種架構設計使得Java程式能夠在不同平台上執行,同時提供記憶體管理、安全性和效能優化等重要功能。理解這個架構有助於開發者更好地把握Java程式的運作機制,為後續的效能調校和問題診斷打下基礎。

JVM記憶體模型詳解

JVM的記憶體模型主要包含以下五個部分:

  1. 方法區(Method Area):

    • 儲存已載入的類別資訊、常量、靜態變數等。
    • 在JDK 8之前,方法區也被稱為「永久代」;JDK 8及以後,改為「元空間」(Metaspace)。
    • 所有執行緒共享此區域。
  2. 堆(Heap):

    • Java程式中最大的一塊記憶體,用於儲存物件實例。
    • 由垃圾回收器管理,自動回收不再使用的物件。
    • 可分為新生代(Young Generation)和老年代(Old Generation)。
    • 所有執行緒共享此區域。
  3. Java堆疊(Java Stack):

    • 每個執行緒都有自己的Java堆疊,用於儲存方法呼叫的資訊。
    • 包含區域變數、部分結果和方法呼叫/返回資訊。
    • 遵循「後進先出」(LIFO)原則。
  4. 程式計數器(Program Counter Register):

    • 每個執行緒都有一個程式計數器,用於指示下一條要執行的指令。
    • 如果執行的是Java方法,計數器記錄的是虛擬機器指令的位址。
    • 如果是本地方法,則為空(undefined)。
  5. 本地方法堆疊(Native Method Stack):

    • 用於支援本地方法(使用C/C++等語言編寫的方法)的執行。
    • 每個執行緒都有自己的本地方法堆疊。

記憶體管理:

  • JVM自動進行記憶體管理,開發者不需要手動分配和釋放記憶體。
  • 垃圾回收器負責識別和清理不再使用的物件,但其執行時機不可預測。

記憶體溢位:

  • 當JVM無法為新的物件分配足夠的記憶體時,會拋出OutOfMemoryError。
  • 常見原因包括記憶體洩漏、配置過大的物件等。

理解JVM的記憶體模型對於編寫高效且穩定的Java程式至關重要。有助於開發者更好地管理資源、診斷問題,並進行效能優化。

(註:在實際應用中,可以提供一個簡單的Java程式碼範例來說明不同記憶體區域的使用。)

JVM執行過程

JVM的執行過程可以分為以下幾個主要階段:

  1. 類別載入:

    • 當Java程式開始執行時,JVM首先載入主類別。
    • 類別載入器負責讀取.class檔案,並將其轉換為JVM中的Class物件。
    • 載入過程遵循委派模型,確保類別的唯一性和安全性。
  2. 連結:

    • 驗證:確保載入的類別符合Java語言規範和JVM規範。
    • 準備:為類別的靜態欄位分配記憶體,並設定初始值。
    • 解析:將符號引用轉換為直接引用(可選)。
  3. 初始化:

    • 執行類別的靜態初始化器和靜態初始化塊。
  4. 執行:

    • JVM執行程式的main方法,開始實際的程式邏輯。
    • 建立物件、呼叫方法、執行運算等。
  5. 垃圾回收:

    • JVM的垃圾回收器在背景執行,自動回收不再使用的物件。
    • 垃圾回收的時機和頻率由JVM自行決定。

以下是一個簡單的Java程式範例,說明JVM執行過程:

public class HelloJVM {
    static {
        System.out.println("靜態初始化塊執行");
    }

    public static void main(String[] args) {
        System.out.println("主方法執行");
        HelloJVM obj = new HelloJVM();
        obj.sayHello();
    }

    public void sayHello() {
        System.out.println("你好,JVM!");
    }
}

執行這個程式時,JVM會經歷以下步驟:

  1. 載入HelloJVM類別。
  2. 連結HelloJVM類別(驗證、準備、解析)。
  3. 初始化HelloJVM類別,執行靜態初始化塊。
  4. 執行main方法。
  5. 在堆中建立HelloJVM物件。
  6. 呼叫sayHello方法。
  7. 程式結束後,垃圾回收器會回收不再使用的物件。

JVM優化技術

JVM採用多種優化技術來提高Java程式的執行效能。以下是一些主要的優化技術:

  1. 即時編譯(JIT Compilation):

    • JVM最初使用直譯器執行位元組碼,但對於頻繁執行的程式碼(熱點程式碼),JIT編譯器會將其編譯為本機機器碼。
    • 這種方法結合直譯和編譯的優點,既保持Java的跨平台特性,又提高執行效率。
  2. 自適應優化:

    • JVM會持續監控程式的執行情況,根據實際運行狀況動態調整優化策略。
    • 例如,根據方法的呼叫頻率決定是否進行內聯優化。
  3. 逸出分析:

    • JVM分析物件的使用範圍,如果發現物件僅在方法內部使用,可能會將堆分配轉換為堆疊分配。
    • 這種優化可以減少垃圾回收的壓力,提高記憶體使用效率。
  4. 記憶體管理優化:

    • 分代垃圾回收:將堆分為新生代和老年代,針對不同年齡的物件採用不同的回收策略。
    • 並行和並發垃圾回收:減少垃圾回收對應用程式執行的影響。
  5. 同步優化:

    • 偏向鎖:對於大多數情況下不存在競爭的同步塊,JVM會使用偏向鎖來減少同步開銷。
    • 鎖消除:通過逸出分析,JVM可能會完全消除不必要的同步。
  6. 類別資料共享:

    • JVM可以將類別資訊儲存在共享檔案中,多個Java可以共用這些資料,減少記憶體使用並加快啟動時間。
  7. AOT編譯(Ahead-of-Time Compilation):

    • 在Java 9中引入,允許在程式執行前將Java程式碼編譯為本機程式碼,進一步提高啟動效能。

這些優化技術大多是自動進行的,開發者通常不需要手動干預。然而,解這些技術可以幫助開發者編寫更適合JVM優化的程式碼,並在需要時進行適當的JVM調校。在實際應用中,可以通過JVM參數來啟用或調整某些優化特性,以適應特定應用程式的需求。

JVM調校與監控

JVM調校是優化Java應用程式效能的重要手段,而有效的監控則是成功調校的基礎。以下是一些關鍵的JVM調校參數和常用的監控工具:

常見JVM參數:

  1. 記憶體相關:

    • -Xms: 設定初始堆大小
    • -Xmx: 設定最大堆大小
    • -XX:NewRatio: 設定新生代和老年代的比例
    • -XX:SurvivorRatio: 設定Eden區與Survivor區的比例
  2. 垃圾回收相關:

    • -XX:+UseG1GC: 使用G1垃圾回收器
    • -XX:+UseConcMarkSweepGC: 使用CMS垃圾回收器
    • -XX:ParallelGCThreads: 設定並行垃圾回收的執行緒數
  3. JIT編譯相關:

    • -XX:CompileThreshold: 設定方法呼叫次數的閾值,超過此值則進行JIT編譯

範例:

java -Xms512m -Xmx1024m -XX:+UseG1GC -XX:ParallelGCThreads=4 -jar myapp.jar

監控工具:

  1. JConsole:

    • Java內建的圖形化監控工具
    • 可監控執行緒、記憶體使用、類別載入等情況
  2. VisualVM:

    • 功能更強大的視覺化監控工具
    • 支援CPU和記憶體分析、執行緒監控等
  3. Java Mission Control (JMC):

    • Oracle提供的高級監控工具
    • 提供詳細的執行時期資訊和效能分析
  4. jstat:

    • 命令列工具,用於監控JVM統計資訊
  5. jmap:

    • 用於生成堆記憶體快照
  6. jstack:

    • 用於生成執行緒堆疊快照

調校建議:

  1. 根據應用程式特性和硬體資源合理設定堆大小。
  2. 選擇適合的垃圾回收器,並根據需求調整參數。
  3. 監控應用程式的記憶體使用情況和GC行為,及時發現問題。
  4. 進行效能測試,比較不同參數設定下的應用程式表現。
  5. 定期檢查和調整,因為應用程式的需求可能隨時間變化。

本篇文章同步刊載: JYI.TW
筆者個人的網站: JUNYI


上一篇
Java進階:鎖定機制與條件變數
下一篇
Java虛擬機器:JVM類別載入機制
系列文
我的Java自學之路:一個轉職者的30篇技術統整30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言